﻿


#include <iostream>
#include <vector>
#include <map>
#include <list>
using namespace std;

struct Point
{
	int _x;
	int _y;
};

class Date
{
public:
	Date(int year = 1970, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Date(int year = 1970, int month = 1, int day = 1)" << endl;
	}

	Date(const Date& d)
		:_year(d._year)
		, _month(d._month)
		, _day(d._day)
	{
		cout << "Date(const Date& d)" << endl;
	}

	~Date()
	{
		_year = 0;
		_month = 0;
		_day = 0;

		cout << "~Date()" << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

void Test1()
{
	// C++98 c语言就有
	int a1[] = { 1, 2, 3, 4, 5 };
	int a2[5] = { 0 };
	Point p = { 1, 2 };

	// C++11开始，内置类型有了自己的默认初始化值。指针类型默认值就是空指针（nullptr）
	cout << int() << endl;
	cout << short() << endl;
	cout << float() << endl;		// 默认值是0，打印时输出的精度自行调整
	cout << double() << endl;
	cout << endl;

	// 内置类型。内置类型的初始化由语言直接处理，不会创建临时对象，而是直接初始化变量。符合语言的高效特性
	int a = 2.5;					// C++98。传统初始化（C风格初始化）。允许隐式转换（如示例会截断小数部分，a = 2）
	int b = { 2 };					// C++11。列表初始化，语法上使用 = 和 {}。调用列表初始化，禁止缩窄转换，赋值号左右的类型必须精确匹配
	// int b = {2.5};				// err	sizeof(double) > sizeof(int)，缩窄转换被禁止
	int c{2};						// C++11。直接列表初始化，此时可省略赋值符号。形式上更简洁
	int* p_int1 = new int();		// 动态分配，需要手动管理内存
	int* p_int2 = new int(7);		// 动态分配，需要手动管理内存

	cout << a << " " << b << " " << c << endl;
	cout << *p_int1 << " " << *p_int2 << endl;
	cout << endl;

	delete p_int1;	// 必须释放申请的空间
	delete p_int2;

	// 自定义类型
	Date d1 = { 2025, 2, 3 };			// 先用{ 2025, 2, 3 }构造一个临时的Date对象，再使用这个临时对象去拷贝构造初始化d1对象。语法上使用构造+拷贝构造，部分编译器会优化为直接构造d1对象
	const Date& d2 = { 2024, 7, 25 };	// d2引⽤的是使用{ 2024, 7, 25 }构造的临时对象

	Date d3 = { 2025 };
	Date d4{ 2025 };				// C++11只有使用{}初始化时，才能省略=
									// 注意，C++11开始容器如vector等的构造函数多了一个直接列表初始化的构造函数，因此vector采用该写法时可以直接调用构造进行初始化
									// 因为其原生语法支持直接构造。直接列表初始化的构造函数原型为：initializer list (6) vector (initializer_list<value_type> il, const allocator_type& alloc = allocator_type());
	//Date d4 2025;					// err 不支持{}和=同时省略
	Date d5 = 2025;					// C++98⽀持单参数的隐式类型转换，{}天然就可以省略
	Date d6 = {2025, 7, 7};			// C++11支持多参数的隐式类型转换。多个参数用{}括起来即可
	Date d7 = { 2025, (short)7, (short)7};	// C++11支持多参数的隐式类型转换。也就说明short类型的7会隐式转换为int类型的7，整型提升，代码可以正常运行
											// 但这种隐式类型转换可能造成漏洞，因此有些容器如vecotr的单参数构造函数使用explicit关键字禁止单参数的隐式类型转换，防止用户意外将数值解释为容器元素（不支持写法如vector<int> v = 5;） 
											// 默认构造的函数原型为：default (1)	explicit vector(const allocator_type & alloc = allocator_type());
	
	vector<Date> v;
	v.reserve(3);					// 提前分配可以容纳3个Date对象的空间，防止vector底层扩容导致Date对象的拷贝构造和析构干扰结果

	v.push_back(d1);				// 尾插有名对象
	v.push_back(Date(2025, 2, 4));	// 尾插匿名对象。语句结束之后匿名对象直接析构
	v.push_back({ 2025, 2, 5 });	// 比起有名对象和匿名对象传参，这⾥{}更有性价比。语句结束之后，使用{ 2025, 2, 5 }构造的临时对象直接析构
	
	// 后定义的先析构。因此vector中的3个Date对象需要析构3次。之后按照d7~d1的顺序析构7次。
	// 
}

class mytest
{
public:
	// 构造函数：记录插入顺序
	mytest(int id) : _id(id) 
	{
		cout << "构造 mytest(" << _id << ") @" << this << endl;
	}

	// 拷贝构造：用于容器插入时的拷贝
	mytest(const mytest& t) : _id(t._id) 
	{
		cout << "拷贝构造 mytest(" << _id << ")" << endl;
	}

	// 析构函数：记录析构顺序
	~mytest() 
	{
		cout << "析构 mytest(" << _id << ") @" << this << endl;
	}
private:
	int _id;
};

// 容器中的对象，析构过程的顺序
void Test2() 
{
	vector<mytest> v;
	v.reserve(6);	

	mytest m4{ 4 };
	mytest m5{ 5 };
	mytest m6{ 6 };
	mytest m7{ 7 };
	mytest m8{ 8 };
	mytest m9{ 9 };

	cout << "===== 插入元素 =====" << endl;
	v.push_back(m4);  
	v.push_back(m5); 
	v.push_back(m6);
	v.push_back(m7);
	v.push_back(m8);
	v.push_back(m9);

	cout << "===== 容器即将销毁 =====" << endl;
	// 当 Test3 函数结束时，vector v 离开作用域，触发销毁
};

void Test3()
{
	std::initializer_list<int> mylist;
	mylist = { 10, 20, 30 };
	cout << sizeof(mylist) << endl;

	// begin和end是initializer_list对象中存的两个指针
	// 这两个指针的值跟i的地址跟接近，说明数组存在栈上
	int i = 0;
	cout << mylist.begin() << endl;
	cout << mylist.end() << endl;
	cout << &i << endl;

	vector<int> v1({ 1,2,3,4,5 });			// 直接构造。因为vector的构造函数中有支持该类型的构造函数
	vector<int> v2 = { 1,2,3,4,5 };			// 构造临时对象+拷⻉临时对象 ==> 有的编译器优化为直接构造
	const vector<int>& v3 = { 1,2,3,4,5 };

	// pair对象的{}初始化和map的initializer_list构造结合到⼀起使用
	map<string, string> dict = { {"sort", "排序"}, {"string", "字符串"} };

	// initializer_list版本的赋值支持
	v1 = { 10,20,30,40,50 };
}

void Test4()
{
	string foo = "foo-string";
	string bar = "bar-string";
	vector<string> myvector;

	myvector.push_back(foo);               // copies
	myvector.push_back(move(bar));         // moves

	cout << foo << " : " << myvector[0] << endl;
	cout << bar << " : " << myvector[1] << endl;

	cout << "myvector contains:";
	for (const auto& x : myvector)
	{
		cout << x << " ";
	}
	cout << endl;
}

void Test51()
{
	// 左值：可以取地址
	// 以下的p、b、c、*p、s、s[0]就是常⻅的左值
	int* p = new int(0);
	*p = 10;
	int b = 1;
	const int c = b;
	string s("111111");
	s[0] = 'x';
	double x = 1.1, y = 2.2;

	// 左值可以取地址
	cout << *p << "	" << &p << endl;
	cout << b << "	" << &b << endl;
	cout << c << "	" << &c << endl;
	cout << s << "	" << &s << endl;
	cout << s[0] << "	" << (void*)&s[0] << endl;	// 避免将&s[0]解释为字符串起始地址而打印成字符串
	cout << x << "	" << &x << endl;
	cout << y << "	" << &y << endl;

	// 右值：不能取地址
	10;				// 字面量
	(void)(x + y);			// 表达式x+y的结果3.3，这是一个临时对象
	(void)fmin(x, y);		// 函数返回的临时结果
	string("1111");	// 匿名对象

	// 上述的右值均不可取地址
	//cout << &10 << endl;				// err 常量上的“&”
	//cout << &(x+y) << endl;			// err “&”要求左值
	//cout << &(fmin(x, y)) << endl;	// err “&”要求左值
	//cout << &string("11111") << endl;	// err “&”要求左值

	int&& a = 10;
	cout << &a << endl;
}

void Test5()
{
	// 左值：可以取地址
	// 以下的p、b、c、*p、s、s[0]就是常⻅的左值
	int* p = new int(0);
	int b = 1;
	const int c = b;
	*p = 10;
	string s("111111");
	s[0] = 'x';
	double x = 1.1, y = 2.2;

	// 左值引⽤给左值取别名
	int& lb = b;
	int*& lp = p;
	int& lrp = *p;
	string& ls = s;
	char& ls0 = s[0];
	cout << "左值引用：" << endl;
	cout << b << " " << p << " " << *p << " " << s << " " << s[0] << endl;
	cout << lb << " " << lp << " " << lrp << " " << ls << " " << ls0 << endl;
	cout << endl;

	// 右值引⽤给右值取别名
	int&& rr1 = 10;
	double&& rr2 = x + y;
	double&& rr3 = fmin(x, y);
	string&& rr4 = string("11111");
	cout << "右值引用：" << endl;
	cout << rr1 << " " << rr2 << " " << rr3 << " " << rr4 << endl;
	cout << endl;

	// 左值引⽤不能直接引⽤右值，但是const左值引⽤可以引⽤右值
	const int& cl1 = 10;
	const double& cl2 = x + y;
	const double& cl3 = fmin(x, y);
	const string& cl4 = string("11111");
	cout << "const左值可以引用右值：" << endl;
	cout << cl1 << " " << cl2 << " " << cl3 << " " << cl4 << endl;
	cout << endl;

	// 右值引⽤不能直接引⽤左值，但是右值引⽤可以引⽤ move(左值)
	int&& rmb = move(b);
	int*&& rmp = move(p);
	int&& rmrp = move(*p);
	string&& rms1 = move(s);
	string&& rms2 = (string&&)s;	// move本质就是强制类型转换
	cout << "右值引用move(左值)：" << endl;
	cout << b << " " << p << " " << *p << " " << s << " " << endl;
	cout << rmb << " " << rmp << " " << rmrp << " " << rms1 << "/" << rms2 << endl;
	cout << endl;

	// b、lb、rr1都是变量表达式，都是左值
	cout << "左值：" << endl;
	cout << &b << endl;
	cout << &lb << endl;
	cout << &rr1 << endl;
	cout << endl;

	/// 这⾥要注意的是，rr1的属性是左值，所以不能再被右值引⽤绑定。除非使用 move(rr1)
	//int&& rrr1 = rr1;		// ERR 无法将右值引用绑定到左值
	int&& rrr1 = move(rr1);	// OK
	cout << rr1 << endl;
	cout << rrr1 << endl << endl;
}

void Test6()
{
	string s1 = "Test";
	//string&& r1 = s1;			// ERR	无法将右值引用绑定到左值
	const string& r2 = s1 + s1; // OK	const的左值引⽤延⻓⽣存期
	//r2 += "Test";				// ERR	没有与这些操作数匹配的 "+=" 运算符。const修饰的值无法修改
	string&& r3 = s1 + s1;		// OK	右值引⽤延⻓⽣存期

	r3 += "Test";				// OK	可以通过到非const的右值引⽤修改

	const string&& r4 = s1 + s1;// OK	可以通过到非const的右值引⽤修改
	//r4 += "Test";				// ERR	没有与这些操作数匹配的 "+=" 运算符。const修饰的值无法修改

	cout << s1 << endl;
	cout << r2 << endl;
	cout << r3 << endl;
	cout << r4 << endl << endl;
}

void f(int& x)
{
	std::cout << "左值引用重载 f(int& x)	" << x << endl;
}

void f(const int& x)
{
	std::cout << "到 const 的左值引用重载 f(const int& x)	" << x << endl;
} 

void f(int&& x)
{
	std::cout << "右值引用重载 f(int&& x)	" << x << endl;
}

void Test7()
{
	int i = 1;
	const int ci = 2;

	f(i);			// 调⽤ f(int&)
	f(ci);			// 调⽤ f(const int&)
	f(3);			// 调⽤ f(int&&)，如果没有 f(int&&) 重载则会调⽤ f(const int&)
	f(std::move(i));// 调⽤ f(int&&)

	// 右值引⽤的变量是左值属性
	int&& x = 3;
	f(x);			// 调⽤ f(int& x)
	f(move(x));		// 调⽤ f(int&& x)
}

#include <iostream>
#include <vector>
#include <map>
using namespace std;

void Test()
{
	std::initializer_list<int> mylist;
	mylist = { 10, 20, 30 };

	cout << sizeof(mylist) << endl;

	// 这⾥begin和end返回的值就是initializer_list对象中存的两个指针
	// 这两个指针的值跟i的地址跟接近，说明数组存在栈上
	int i = 0;
	cout << mylist.begin() << endl;
	cout << mylist.end() << endl;
	cout << &i << endl;

	// initializer_list的{}列表中可以有任意多个值
	vector<int> v1({ 1,2,3,4,5 });			// 直接构造
	vector<int> v2 = { 1,2,3,4,5 };			// 构造临时对象+临时对象拷⻉，部分编译器如vs2019优化为直接构造
	vector<double> v3({ 1.1, 2.2, 3.3 });	// 直接构造
	const vector<int>& v4 = { 1,2,3,4,5 };

	// pair对象的{}初始化和map的initializer_list构造结合
	map<string, string> dict = { {"sort", "排序"}, {"string", "字符串"} };

	// initializer_list版本的赋值⽀持
	v1 = { 10,20,30,40,50 };
}

#include "String.h"

void Test8()
{
	yyp::string s1("xxxxx");				// 字符串构造
	yyp::string s2 = s1;					// 拷贝构造
	yyp::string s3 = yyp::string("yyyyy");	// 字符串构造+移动构造，部分编译器优化后（C++ 17之后）直接字符串构造
	yyp::string s4 = move(s1);				// 移动构造，注意s1的资源被s4拿走
	cout << "******************************" << endl << endl;

	if (nullptr == s1.c_str())
	{
		cout << "s1：nullptr" << endl;
	}
	cout << "s2：" << s2 << endl;
	cout << "s3：" << s3 << endl;
	cout << "s4：" << s4 << endl << endl;

	s1 = s3;
	cout << "s1：" << (void*)s1.c_str() << " " << s1 << endl << endl;

	s1 = "111";
	cout << "s1：" << (void*)s1.c_str() << " " << s1 << endl;
	cout << "******************************" << endl << endl;
}

namespace yyp
{
	string addStrings(string num1, string num2)
	{
		string res;
		int carry = 0;  // 进位

		for (int end1 = num1.size() - 1, end2 = num2.size() - 1; end1 >= 0 || end2 >= 0;)
		{
			int a = end1 >= 0 ? num1[end1--] - '0' : 0;
			int b = end2 >= 0 ? num2[end2--] - '0' : 0;
			int sum = a + b + carry;

			carry = sum / 10;
			sum %= 10;
			res += (sum + '0');
		}
		if (1 == carry)
			res += '1';
		reverse(res.begin(), res.end());

		return res;
	}

	void Test9()
	{
		// 场景1
		/*string ret1 = addStrings("11111", "2222");
		cout << ret1 << endl << endl;*/

		// 场景2
		string ret2;
		ret2 = addStrings("11111", "2222");
		cout << ret2 << endl << endl;
	}
}

#include "List.h"
void Test10()
{
	yyp::list<yyp::string> lt;
	cout << "*************************" << endl << endl;

	yyp::string s1("111111111111111111111");
	yyp::string s2("111111111111111111111");

	lt.push_back(s1);
	lt.emplace_back(s2);
	cout << endl << endl;

	lt.push_back(yyp::string("22222222222222222222222222222"));
	lt.emplace_back(yyp::string("22222222222222222222222222222"));
	cout << endl << endl;


	lt.push_back("3333333333333333333333333333");
	lt.emplace_back("3333333333333333333333333333");
	cout << endl << endl;

	lt.push_back(move(s1));
	lt.emplace_back(move(s2));
	cout << endl << endl;

	/*list<string> lt1;
	string s3("111111111111111111111");

	lt1.emplace_back(s3, s3, s3);*/
}

// 由于引⽤折叠限定，f1实例化以后总是⼀个左值引⽤
template<class T>
void f1(T& x)
{}

// 由于引⽤折叠限定，f2实例化后可以是左值引⽤，也可以是右值引⽤
template<class T>
void f2(T&& x)
{}

void Test11()
{
	typedef int& lref;
	typedef int&& rref;

	int n = 0;
	lref& r1 = n;	// r1 的类型是 int&
	lref&& r2 = n;	// r2 的类型是 int&
	rref& r3 = n;	// r3 的类型是 int&
	rref&& r4 = 1;	// r4 的类型是 int&&

	// 没有折叠->实例化为void f1(int& x)
	f1<int>(n);
	//f1<int>(0); // ERR “void f1<int>(T &)”: 无法将参数 1 从“int”转换为“T &”

	// 折叠->实例化为void f1(int& x)
	f1<int&>(n);
	//f1<int&>(0); // ERR “void f1<int>(T &)”: 无法将参数 1 从“int”转换为“T”

	// 折叠->实例化为void f1(int& x)
	f1<int&&>(n);
	//f1<int&&>(0); // ERR “void f1<int&&>(T)”: 无法将参数 1 从“int”转换为“T”

	// 折叠->实例化为void f1(const int& x)
	f1<const int&>(n);
	f1<const int&>(0);

	// 折叠->实例化为void f1(const int& x)
	f1<const int&&>(n);
	f1<const int&&>(0);

	// 没有折叠->实例化为void f2(int&& x)
	//f2<int>(n); // ERR “void f2<int>(T &&)”: 无法将参数 1 从“int”转换为“T &&”
	f2<int>(0);

	// 折叠->实例化为void f2(int& x)
	f2<int&>(n);
	//f2<int&>(0); // ERR “void f2<int&>(T)”: 无法将参数 1 从“int”转换为“T”

	// 折叠->实例化为void f2(int&& x)
	//f2<int&&>(n); // ERR “void f2<int&&>(T)”: 无法将参数 1 从“int”转换为“T”
	f2<int&&>(0);
}

template<class T>
void Function1(T& t)
{
	int a = 0;
	T x = a;

	//x++;
	cout << &a << endl;
	cout << &x << endl;
}

template<class T>
void Function2(T&& t)
{
	int a = 0;
	T x = a;

	//x++;
	cout << &a << endl;
	cout << &x << endl << endl;
}

void Test12()
{
	cout << "************右值************" << endl;
	//Function1(10);		// ERR
	Function2(10);			// 10是右值，推导出T为int，模板实例化为void Function2(int&& t)

	int a = 10;

	cout << "************左值************" << endl;
	Function1(a);			// a是左值，推导出T为int，模板实例化为void Function(int& t)
	Function2(a);			// a是左值，推导出T为int&，int& && 引⽤折叠为 int&，模板实例化为void Function2(int& t)

	cout << "********move(左值)***********" << endl;
	//Function1(std::move(a)));	// ERR
	Function2(std::move(a));	// std::move(a)是右值，推导出T为int，模板实例化为void Function2(int&& t)

	const int b = 8;

	cout << "**********const 左值**********" << endl;
	Function1(b);			// b是左值，推导出T为const int，模板实例化为void Function1(const int& t)
	Function2(b);			// b是左值，推导出T为const int&，const int& && 引⽤折叠为 const int&，模板实例化为void Function2(const int& t)
							// Function1和Function2内部的x++均会编译报错（“x”: 不能给常量赋值）

	cout << "**********const 右值**********" << endl;
	Function1(std::move(b)); //	std::move(b)右值，推导出T为const int，模板实例化为void Function(const int&& t)
	Function2(std::move(b)); // std::move(b)右值，推导出T为const int，模板实例化为void Function(const int&& t)
							 // Function1和Function2内部的x++均会编译报错（“x”: 不能给常量赋值）
}

void Test13()
{
	int&& ra1 = 7;
	int&& rra1 = move(ra1);
	//int&&&& rra2 = 9;	// ERR 不允许使用引用的引用(本意是想定义右值引用的右值引用)

	cout << "右值引用 " << ra1 << endl;
	cout << "右值引用的右值引用 " << rra1 << " " << ra1 << endl;

	int a = 10;
	int& la1 = a;
	int& lla1 = la1;
	cout << "左值引用 " << la1 << " " << a << endl;
	cout << "左值引用的左值引用 " << lla1 << " " << la1 << " " << a << " " << endl;

	int& lra2 = ra1;
	cout << "右值引用的左值引用 " << lra2 << " " << ra1 << endl;

	int&& rla2 = move(lra2);
	cout << "左值引用的右值引用 " << rla2 << " " << lra2 << " " << ra1 << endl;

	cout << typeid(ra1).name() << endl;
	cout << typeid(rra1).name() << endl;
	cout << typeid(a).name() << endl;
	cout << typeid(la1).name() << endl;
	cout << typeid(lla1).name() << endl;
	cout << typeid(lra2).name() << endl;
	cout << typeid(rla2).name() << endl;
}

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }

template<class T>
void Function(T&& t)
{
	//Fun(t);
	Fun(forward<T>(t));
}

void Test14()
{
	
	Function(10); // 10是右值，推导出T为int。完美转发传给Fun的参数类型是T&& = int&&，右值引用

	int a;

	
	Function(a); // a是左值，推导出T为int&。完美转发传给Fun的参数类型是T&& = int&&&，引用折叠为左值引用 int&

	
	Function(std::move(a)); // std::move(a)是右值，推导出T为int。完美转发传给Fun的参数类型是T&& = int&&，右值引用

	const int b = 8;

	
	Function(b); // b是左值，推导出T为const int&。完美转发传给Fun的参数类型是T&& = const int&&&，引用折叠为左值引用 const int&

	
	Function(std::move(b)); // std::move(b)右值，推导出T为const int。完美转发传给Fun的参数类型是T&& = const int&&，const 右值引用
}

//template <class ... Args>
//void Print(Args&& ... args)
//{
//	cout << sizeof ...(args) << " ";
//	cout << sizeof... (args) << " ";
//	cout << sizeof ... (args) << endl;
//}
//
//void Test15()
//{
//	double x = 2.2;
//
//	Print();						// 包⾥有0个参数
//	Print(1);						// 包⾥有1个参数
//	Print(1, string("xxxxx"));		// 包⾥有2个参数
//	Print(1.1, string("xxxxx"), x); // 包⾥有3个参数
//}

void ShowList()
{
	// 递归的终止条件。参数包个数是0个时，直接匹配该函数
	cout << endl;
}

template <class T, class... Args>
void ShowList(T&& t, Args&&... args)
{
	// 第⼀个参数传给t，剩下N-1个传给args
	cout << t << " ";
	ShowList(args...);
}

// 编译时递归推导解析参数
template <class... Args>
void Print1(Args&&... args)
{
	// args是N个参数的参数包
	// 调⽤ShowList，参数包的第⼀个参数传给t，剩下N-1个传给第⼆个参数包
	ShowList(args...);
}

template <class T>
T&& GetArg(T&& t)
{
	cout << t << " ";
	return forward<T>(t);
}

template <class... Args>
void Arguments(Args&&... args)
{}

template <class... Args>
void Print2(Args&&... args)
{
	// 写法1 参数包扩展
	// 注意GetArg必须返回传入的对象，这样才能组成参数包传给Arguments
	// GetArg是核心函数。它将参数包 args 中的每个元素分别传递给 GetArg，而 GetArg 的所有返回值又会组合成新的参数包（传给 Arguments）
	Arguments(GetArg(args)...);

	// 写法2 C++17的折叠表达式
	//(GetArg(forward<Args>(args)), ...);

	cout << endl;

	// 原理讲解，例如 Print2(1.1, string("xxxxx"), x);
	// 写法1和写法逻辑一致。本质可以理解为编译器编译时，包的扩展模式将函数模板扩展实例化为如下函数
	//void Print2(int&& a, string&& b, double& c)
	//{
	//	Arguments(GetArg(a), GetArg(b), GetArg(c));
	//}
	// 这里可以看到C++11开始的语法设计思维跳跃得太厉害
}

void Test15()
{
	double x = 2.2;

	Print1();					
	Print1(1);					
	Print1(1, string("xxxxx"));		
	Print1(1.1, string("xxxxx"), x);

	Print2();
	Print2(1);
	Print2(1, string("xxxxx"));
	Print2(1.1, string("xxxxx"), x);
}

void Test16()
{
	yyp::list<yyp::string> lt1;
	cout << "**************************************" << endl;

	yyp::string s1("111111111111");
	yyp::string s2("111111111111");
	cout << endl << endl;

	lt1.push_back(s1);			// 左值。拷贝构造
	lt1.emplace_back(s1);		// 同理
	cout << endl << endl;

	lt1.push_back(move(s1));	// 右值。移动构造
	lt1.emplace_back(move(s2));	// 同理
	cout << endl << endl;

	// 直接把可以构造string的const char*参数包往下传，直接用const char*参数包构造string
	lt1.push_back("111111111111");
	lt1.emplace_back("111111111111");
	cout << "\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" << endl;

	yyp::list<pair<yyp::string, int>> lt2;
	cout << "**************************************" << endl;

	pair<yyp::string, int> kv1("苹果", 1);
	pair<yyp::string, int> kv2("苹果", 1);
	cout << endl << endl;
	
	lt2.push_back(kv1);			// 左值。拷贝构造
	lt2.emplace_back(kv2);		// 同理
	cout << endl << endl;

	lt2.push_back(move(kv1));	// 右值。移动构造
	lt2.emplace_back(move(kv2));// 同理
	cout << endl << endl;

	// 直接把构造pair的参数包往下传，直接⽤pair参数包构造pair
	lt2.push_back("苹果", 1);	
	lt2.emplace_back("苹果", 1); 
	cout << endl << endl;
}

void Test17()
{
	yyp::list<yyp::string> lt;
	cout << endl;

	yyp::string s1("111");
	cout << endl;

	lt.push_back(s1);
	cout << endl;

	lt.push_back(move(s1));
	cout << endl;

	const yyp::string s2("222");
	cout << endl;

	const char* str = "222";

	lt.push_back(str);
	cout << endl;

	lt.push_back("222");
	cout << endl;

	lt.push_back(s2);
	cout << endl;
}

void Test18()
{
	class Person
	{
	public:
		Person(const char* name = "", int age = 0)
			: _name(name)
			, _age(age)
		{}

		// 析构函数 、拷⻉构造、拷⻉赋值重载只要实现其中一个，移动构造和移动赋值就不会自动生成

		Person(const Person& p)
			: _name(p._name)
			, _age(p._age)
		{}

		/*Person& operator=(const Person& p)
		{
			if(this != &p)
			{
				_name = p._name;
				_age = p._age;
			}

			return *this;
		}*/

		/*~Person()
		{}*/

	private:
		yyp::string _name;
		int _age;
	};


	Person p1;
	Person p2 = p1;
	Person p3 = std::move(p1);	// 有移动构造时，会调用yyp::string的移动构造
	Person p4;

	p4 = std::move(p2);			// 有移动赋值时，会调用yyp::string的移动赋值
}

void Test19()
{
	class Person
	{
	public:
		Person(const char* name = "", int age = 0)
			: _name(name)
			, _age(age)
		{}

		// 同时实现了析构函数 、拷⻉构造、拷⻉赋值重载，正常情况下不会生成默认的移动构造和移动赋值
		// 但是可以使用 default 强制生成默认函数

		Person(Person&& p) = default;

		Person(const Person& p)
			: _name(p._name)
			, _age(p._age)
		{}

		Person& operator=(Person&& p) = default;

		Person& operator=(const Person& p)
		{
			if(this != &p)
			{
				_name = p._name;
				_age = p._age;
			}

			return *this;
		}

		~Person()
		{}

	private:
		yyp::string _name;
		int _age;
	};


	Person p1;
	Person p2 = p1;
	Person p3 = std::move(p1);
	Person p4;

	p4 = std::move(p2);
}

void Test20()
{
	class Person
	{
	public:
		Person(const char* name = "", int age = 0)
			: _name(name)
			, _age(age)
		{}

		// 正常情况下，这里会自动生成默认的移动构造和移动赋值
		// 但是使用 delete 可以强制删除某默认函数
		Person(Person&& p) = delete;

		// 移动构造会干预默认拷贝构造的生成，此时可以显式声明拷贝构造
		/*Person(const Person& p)
			: _name(p._name)
			, _age(p._age)
		{}*/
		//Person(const Person& p) = default;

	private:
		yyp::string _name;
		int _age;
	};

	Person p1;
	//Person p2 = std::move(p1);// ERR 尝试引用已删除的函数
	Person p3 = p1;			// ERR 尝试引用已删除的函数。具有用户定义的移动构造函数，因此已隐式删除函数
}

void Test21()
{
	// 1、捕捉列表为空不能省略
	auto add1 = [](const int& x, const int& y) ->int 
	{
		return x + y;
	};

	// 2、返回值可省略，通过返回的对象自动推导
	auto add2 = [](const int& x, const int& y)
	{
		return x + y;
	};

	// 3、参数列表为空时可省略
	// 4、函数体不可省略
	auto Hello = [] 
	{
		cout << "hello world" << endl;
	};

	auto swap = [](int& a, int& b) 
	{
		int tmp = a;
		a = b;
		b = tmp;
	};

	cout << add1(1, 2) << endl;
	cout << add2(1, 2) << endl;
	Hello();
	
	int a = 2, b = 7;

	cout << a << " " << b << endl;
	swap(a, b);
	cout << a << " " << b << endl;
}

int x = 7;
int gl = 0;

// 捕捉列表必须为空
auto global1 = []()
{
	cout << gl << " ";
	++gl;
	cout << gl << " ";
};

// vs2019的宽容处理
auto global2 = [=]
{
	cout << gl << " ";
	++gl;
	cout << gl << " ";
};

// vs2019的宽容处理
auto global3 = [&]
{
	cout << gl << " ";
	++gl;
	cout << gl << " ";
};

void Test22()
{
	// 只能⽤当前lambda局部域捕捉的对象和全局对象
	int a = 0, b = 1, c = 2, d = 3;

	cout << "\t" << a << " " << b << " " << c << " " << d << endl << endl;

	auto func1 = [a, &b]
	{
		// 值捕捉的变量不能修改，引⽤捕捉的变量可以修改
		//++a;
		++b;
		int ret = a + b;
		return ret;
	};
	cout << "func1():" << func1() << endl;
	cout << "\t" << a << " " << b << " " << c << " " << d << endl << endl;

	// 隐式值捕捉。⽤了哪些变量就自动捕捉哪些变量
	auto func2 = [=]
	{
		int ret = a + b + c;
		return ret;
	};
	cout << "func2():" << func2() << endl;
	cout << "\t" << a << " " << b << " " << c << " " << d << endl << endl;

	// 隐式值捕捉。传值捕捉本质是⼀种拷⻉,并且形参默认被const修饰
	// mutable修饰参数列表相当于去掉形参的const属性
	// 修改不会影响实参的值，因为是⼀种拷⻉
	auto func3 = [=]()mutable
	{
		++a;
		++b;
		++c;
		++d;

		int ret = a + b + c;
		return ret;
	};
	cout << "func3():" << func3() << endl;
	cout << "\t" << a << " " << b << " " << c << " " << d << endl << endl;

	// 隐式引⽤捕捉。⽤了哪些变量就自动捕捉哪些变量
	auto func4 = [&]
	{
		a += 3;
		b += 1;
		c += 1;
	};
	func4();
	cout << "func4():" << endl;
	cout << "\t" << a << " " << b << " " << c << " " << d << endl << endl;


	// 混合捕捉1
	//auto func5 = [&, a, b, &c] {}; //	ERR 当默认捕获模式为通过引用捕获时，无法显式捕获“&c”(&)
	auto func5 = [&, a, b]
	{
		/*++a;	// 值捕捉，不可修改
		++b;*/
		c += 2;
		d += 2;

		return a + b + c + d;
	};
	cout << "func5():" << func5() << endl;
	cout << "\t" << a << " " << b << " " << c << " " << d << endl << endl;

	// 混合捕捉2
	//auto func6 = [=, &a, &b, c] {}; // ERR 当默认捕获模式为按复制捕获时，需要“&c”(=)
	auto func6 = [=, &a, &b]
	{
		a += 2;
		b += 2;
		//++c;	// 值捕捉，不可修改
		//++d;
		//cout << m << endl;		//	ERR	静态局部变量m在func6之后才定义，无法使用
		return a + b + c + d;
	};
	cout << "func6():" << func6() << endl;
	cout << "\t" << a << " " << b << " " << c << " " << d << endl << endl;

	// 全局变量和局部的静态不能捕捉，也不需要捕捉
	static int m = 3;
	auto func7 = []
	{
		int ret = x + m;
		return ret;
	};
	cout << "func7():" << func7() << endl << endl;

	// 函数局部域中的lambda，不能捕捉全局变量和局部的静态变量
	//auto func8 = [x, m] {};	// ERR	“x”: lambda 捕获必须是来自封闭函数范围的变量
	//auto func8 = [&x, &m]{};	// ERR	“m”: 简单捕获必须是含自动存储持续时间(在 lambda 的访问范围中声明)的变量

	global1();
	cout << gl << endl;

	global2();
	cout << gl << endl;

	global3();
	cout << gl << endl;
}

void Test23()
{
	// 水果
	struct Goods
	{
		string _name;	// 名字
		double _price;	// 价格
		int _vc;		// 维生素C的含量
		// ...

		Goods(const char* str, double price, int vc)
			: _name(str)
			, _price(price)
			, _vc(vc)
		{}
	};

	struct ComparePriceLess
	{
		bool operator()(const Goods& gl, const Goods& gr)
		{
			return gl._price < gr._price;
		}
	};

	struct ComparePriceGreater
	{
		bool operator()(const Goods& gl, const Goods& gr)
		{
			return gl._price > gr._price;
		}
	};

	vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3}, { "菠萝", 1.5, 4 } };

	// 实现仿函数对象或者函数指针⽀持商品中不同项的⽐较，还是⽐较⿇烦
	sort(v.begin(), v.end(), ComparePriceLess());
	sort(v.begin(), v.end(), ComparePriceGreater());

	// 使用lambda
	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
		return g1._price < g2._price;
		});

	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
		return g1._price > g2._price;
		});

	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
		return g1._vc < g2._vc;
		});

	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
		return g1._vc > g2._vc;
		});
		
}

void Test24()
{
	class Rate
	{
	public:
		Rate(double rate)
			: _rate(rate)
		{}

		double operator()(double money, int year)
		{
			return money * _rate * year;
		}

	private:
		double _rate;
	};

	double rate = 0.49;
	Rate r1(rate);	// 函数对象

	// lambda
	auto r2 = [rate](double money, int year) {
		return money * rate * year;
	};

	r1(10000, 2);
	r2(10000, 2);

	auto func1 = [] {
		cout << "hello world" << endl;
	};
	func1();
}

#include<functional>

int Func1(int a, int b)
{
	return a + b;
}

struct Func2
{
public:
	int operator() (int a, int b)
	{
		return a + b;
	}
};

class Plus
{
public:
	Plus(int n = 10)
		:_n(n)
	{}

	static int plusi(int a, int b)
	{
		return a + b;
	}

	double plusd(double a, double b)
	{
		return (a + b) * _n;
	}

private:
	int _n;
};

void Test25()
{
	Plus pd;

	// 包装各种可调⽤对象
	function<int(int, int)> f1 = Func1;		// 包装函数
	function<int(int, int)> f2 = Func2();	// 包装仿函数
	function<int(int, int)> f3 = [](int a, int b) {return a + b; }; // 包装lambda表达式

	// 包装静态成员函数
	// 成员函数要指定类域并且前⾯加&才能获取地址
	function<int(int, int)> f4 = &Plus::plusi;

	// 包装普通成员函数
	// 非静态成员函数有⼀个隐含的this指针。绑定时使用指针、左值对象、右值对象都能提供有效的地址作为this
	function<double(Plus*, double, double)> f5 = &Plus::plusd;
	function<double(Plus, double, double)> f6 = &Plus::plusd;
	function<double(Plus&&, double, double)> f7 = &Plus::plusd;

	cout << f1(1, 1) << endl;
	cout << f2(1, 1) << endl;
	cout << f3(1, 1) << endl;
	cout << f4(1, 1) << endl;
	cout << f5(&pd, 1.1, 1.1) << endl;
	cout << f6(pd, 1.1, 1.1) << endl;
	cout << f7(move(pd), 1.1, 1.1) << endl;
	cout << f7(Plus(), 1.1, 1.1) << endl;

	// 空目标的funciton
	function<void()> empty_func;
	if (!empty_func) 
	{
		std::cout << "empty_func 未绑定任何函数\n";
	}

	// 只能包装函数类型的可调用对象
	//function<int> intf; // err
}

int Sub(int a, int b)
{
	return (a - b) * 10;
}

int SubX(int a, int b, int c)
{
	return (a - b - c) * 10;
}

void Test26()
{
	using placeholders::_1;
	using placeholders::_2;
	using placeholders::_3;

	// bind本质是返回的⼀个仿函数对象
	auto sub1 = bind(Sub, _1, _2);
	auto sub2 = bind(Sub, _2, _1);	// 调整参数顺序（不常⽤）
	auto sub3 = bind(Sub, 100, _1);	// 绑定第1个参数
	auto sub4 = bind(Sub, _1, 100);	// 绑定第2个参数

	cout << sub1(10, 5) << endl;
	cout << sub2(10, 5) << endl << endl;
	cout << sub3(5) << endl;
	cout << sub4(5) << endl << endl;
	
	// bind绑定某些参数，调整参数个数（常用）
	auto sub5 = bind(SubX, 100, _1, _2);// 绑定第1个参数
	auto sub6 = bind(SubX, _1, 100, _2);// 绑定第2个参数
	auto sub7 = bind(SubX, _1, _2, 100);// 绑定第3个参数
	auto sub8 = bind(SubX, _2, _1, 100);// 绑定第3个参数+调整参数顺序

	cout << sub5(5, 1) << endl;
	cout << sub6(5, 1) << endl;
	cout << sub7(5, 1) << endl;
	cout << sub8(5, 1) << endl << endl;

	// 使用bind绑定第一个参数，后续使用时第一个参数无需传递
	Plus pd;
	function<double(Plus&&, double, double)> f6 = &Plus::plusd;
	function<double(double, double)> f7 = bind(&Plus::plusd, Plus(), _1, _2);// 调整参数个数

	cout << f6(move(pd), 1.1, 1.1) << endl;
	cout << f6(Plus(), 1.1, 1.1) << endl;
	cout << f7(1.1, 1.1) << endl << endl;

	// 计算复利的利息。后一年的本金是前一年本金和利息的总和，一年结息一次
	auto func1 = [](double rate, double money, int year)->double {
		double ret = money;
		for (int i = 0; i < year; i++)
		{
			ret += ret * rate;
		}
		return ret - money;
	};

	// 使用bind固定利率和结息次数，计算不同⾦额根据复利得到的净利息
	function<double(double)> func_1_3 = bind(func1, 0.015, _1, 3);
	function<double(double)> func_1_5 = bind(func1, 0.015, _1, 5);
	function<double(double)> func_1_10 = bind(func1, 0.025, _1, 10);
	function<double(double)> func_1_30 = bind(func1, 0.035, _1, 30);

	cout << func_1_3(1000000) << endl;
	cout << func_1_5(1000000) << endl;
	cout << func_1_10(1000000) << endl;
	cout << func_1_30(1000000) << endl;
}

int main()
{
	//Test();
	//Test1();
	//Test2(); // 待验证
	//Test3();
	//Test4();
	//Test51();
	//Test5();
	//Test6();
	//Test7();
	//Test8();
	//yyp::Test9();
	//yyp::TestStr();
	//Test10();
	//Test11();
	//Test12();
	//Test13();
	//Test14();
	//Test15();
	//Test16();
	//Test17();
	//Test18();
	/*Test19();
	cout << endl;*/
	Test20();
	//Test21();
	//Test22();
	//Test23();
	//Test24();
	//Test25();
	//Test26();

	return 0;
}






















